package com.vcredit.creditcat.manager;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.dubbo.config.annotation.Service;
import com.vcredit.bird.api.IAccumulationService;
import com.vcredit.bird.util.CommonUtil;
import com.vcredit.bird.vo.accumulation.AccDetail;
import com.vcredit.bird.vo.accumulation.AccInit;
import com.vcredit.bird.vo.accumulation.AccParentParam;
import com.vcredit.bird.vo.accumulation.AccProvinceParam;
import com.vcredit.bird.vo.accumulation.CityParam;
import com.vcredit.creditcat.api.IAuthAccumulationManager;
import com.vcredit.creditcat.dto.AccCityDto;
import com.vcredit.creditcat.dto.AccInitDto;
import com.vcredit.creditcat.dto.AccLoginDto;
import com.vcredit.creditcat.enumtype.AuthAccEnum;
import com.vcredit.creditcat.enumtype.AuthAccumulationStatusEnum;
import com.vcredit.creditcat.enumtype.AuthItemEnum;
import com.vcredit.creditcat.enumtype.CustIsRealEnum;
import com.vcredit.creditcat.exception.BirdRequestFailException;
import com.vcredit.creditcat.model.AuthAccumulation;
import com.vcredit.creditcat.model.AuthItem;
import com.vcredit.creditcat.model.AuthLog;
import com.vcredit.creditcat.model.AuthSocial;
import com.vcredit.creditcat.model.Cust;
import com.vcredit.creditcat.service.AuthAccumulationService;
import com.vcredit.creditcat.service.AuthLogService;
import com.vcredit.creditcat.service.AuthSocialService;
import com.vcredit.creditcat.service.CustService;
import com.vcredit.creditcat.util.ConcurrentDateUtil;
import com.vcredit.creditcat.util.Utility;
import com.vcredit.framework.annotation.Log;
import com.vcredit.framework.exception.BaseException;
import com.vcredit.framework.util.BeanUtil;
import com.vcredit.framework.util.JacksonUtil;

@Service(protocol = { "protocol1" }, version = "1.0" , timeout=120000)
public class AuthAccumulationManager implements IAuthAccumulationManager {

	@Autowired
	@Qualifier(value = "accumulationServiceImpl")
	private IAccumulationService accumulationService;
	@Autowired
	@Qualifier(value = "socialServiceImpl")
	private IAccumulationService socailService;
	@Autowired
	private AuthAccumulationService authAccumulationService;
	@Autowired
	private AuthSocialService authSocialService;
	@Autowired
	private CreditCatProcessManager creditCatProcessManager;
	@Autowired
	private AuthLogService authLogService;
	@Autowired
	private CustService custService;
	
	@Override
	public List<AccCityDto> supportCity(Long processId, Integer type) throws Exception {
		List<AccProvinceParam> param = null;//
		if (type == AuthAccEnum.SOCIAL.getCode())// 社保
			param = socailService.accGetSupportCity();
		else if (type == AuthAccEnum.ACCUMULATION.getCode())// 公积金
			param = accumulationService.accGetSupportCity();
		List<AccCityDto> accCityDtos = new ArrayList<AccCityDto>();
		for (AccProvinceParam acc : param) {
			List<CityParam> cityParam = acc.getCityLevel();
			if (cityParam != null && cityParam.size() > 0) {
				List<AccCityDto> accCity = BeanUtil.copy(cityParam, AccCityDto.class);
				accCityDtos.addAll(accCity);
			}
		}
		return accCityDtos;
	}

	@Override
	public String queryForm(String city, Long processId, Integer type) throws Exception {
		String paramString = null;
		if (type == AuthAccEnum.SOCIAL.getCode())// 社保
			paramString = socailService.accQueryFormByCity(city);
		else if (type == AuthAccEnum.ACCUMULATION.getCode())// 公积金
			paramString = accumulationService.accQueryFormByCity(city);
		return paramString;
	}

	@Override
	public AccInitDto init(String city, Long processId, Integer type) throws Exception {
		AccInit init = null;
		if (type == AuthAccEnum.SOCIAL.getCode()) {// 社保
			init = socailService.accInit(city);
			AuthSocial authAcc = authSocialService.findByProcessId(processId);
			if (authAcc == null) {
				AuthSocial auth = new AuthSocial(processId, init.getToken(), city,
						AuthAccumulationStatusEnum.INIT.getCode());
				authSocialService.insert(auth);
			} else {
				AuthSocial socialItem = new AuthSocial(authAcc.getAuthSocialId(), processId, init.getToken(), city,
						AuthAccumulationStatusEnum.INIT.getCode());
				if(authAcc.computeExpire()){
					socialItem.setExpiredTime("");
				}
				authSocialService.update(socialItem);
			}
		} else if (type == AuthAccEnum.ACCUMULATION.getCode()) {
			init = accumulationService.accInit(city);
			AuthAccumulation authAcc = authAccumulationService.findByProccessId(processId);
			if (authAcc == null) {
				AuthAccumulation auth = new AuthAccumulation(processId, init.getToken(), city,
						AuthAccumulationStatusEnum.INIT.getCode());
				authAccumulationService.insert(auth);
			} else{
				AuthAccumulation accItem = new AuthAccumulation(authAcc.getAuthAccId(), processId, init.getToken(),
						city, AuthAccumulationStatusEnum.INIT.getCode());
				if(authAcc.computeExpire()){
					accItem.setExpiredTime("");
				}
				authAccumulationService.update(accItem);
			}
		}
		AccInitDto initDto = new AccInitDto();
		BeanUtil.copy(init, initDto);
		return initDto;
	}

	@Override
	@Log
	public String login(Long processId, AccLoginDto input, Integer type,String idNo, Long custId) throws Exception {
		Map<String, Object> params = JacksonUtil.Json2Map(input.getFormData());
		AccParentParam result = null;
		params.put("bustype", "");
		params.put("city", input.getCity());
		if(params.get("identitycard") == null || params.get("identitycard").equals("")){
			params.put("identitycard", idNo);
		}else if(!idNo.equalsIgnoreCase((String)params.get("identitycard")))
			throw new Exception("请输入实名的身份证号");
		if(type == AuthAccEnum.SOCIAL.getCode()){//社保
			result = socailService.accLogin(input.getCity(), params);
			itemLoginSuccess(processId, custId, AuthItemEnum.SOCIAL_CREDIT, type);
			
		}
		else if(type == AuthAccEnum.ACCUMULATION.getCode()){
			result = accumulationService.accLogin(input.getCity(), params);
			itemLoginSuccess(processId, custId, AuthItemEnum.FUND_CREDIT, type);
		}
		return result.getStatusDescription();
	}
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	private void itemLoginSuccess(Long processId, Long custId, AuthItemEnum authItem, Integer type) throws Exception{
		if(type == AuthAccEnum.SOCIAL.getCode()){ //社保
			AuthSocial authAcc = authSocialService.findByProcessId(processId);
			AuthSocial authSocial = new AuthSocial( 
						authAcc.getAuthSocialId(),
						null,
						AuthAccumulationStatusEnum.SUCCESS.getCode(),
						null);
			authSocialService.update(authSocial);
		}
		else if(type == AuthAccEnum.ACCUMULATION.getCode()){//公积金
			AuthAccumulation authAcc = authAccumulationService.findByProccessId(processId);
			AuthAccumulation accAuth = new AuthAccumulation(authAcc.getAuthAccId(),null,AuthAccumulationStatusEnum.SUCCESS.getCode(),null);
			authAccumulationService.update(accAuth);
		}
	}
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	private void itemDone(Long processId, Long custId, AuthItemEnum authItem, Integer type) throws Exception{
		if(type == AuthAccEnum.SOCIAL.getCode()){
			AuthSocial authAcc = authSocialService.findByProcessId(processId);
			AuthSocial authSocial = new AuthSocial(
						authAcc.getAuthSocialId(),
						ConcurrentDateUtil.formatDateTime(new Date()),
						AuthAccumulationStatusEnum.AUTH_SUCCESS.getCode(),
						CustIsRealEnum.Yes.getCode());
			authSocial.setExpiredTime(ConcurrentDateUtil.formatDateTime(ConcurrentDateUtil.addDayTime(new Date(), 30)));
			authSocialService.update(authSocial);
			authLogService.insert(new AuthLog(processId, custId, authItem.getCode(), authSocial.getExpiredTime(), new Date()));
		}
		else if(type == AuthAccEnum.ACCUMULATION.getCode()){//公积金
			AuthAccumulation authAcc = authAccumulationService.findByProccessId(processId);
			AuthAccumulation accAuth = new AuthAccumulation(
						authAcc.getAuthAccId(),
						ConcurrentDateUtil.formatDateTime(new Date()),
						AuthAccumulationStatusEnum.AUTH_SUCCESS.getCode(),CustIsRealEnum.Yes.getCode());
			accAuth.setExpiredTime(ConcurrentDateUtil.formatDateTime(ConcurrentDateUtil.addDayTime(new Date(), 30)));
			authAccumulationService.update(accAuth);
			authLogService.insert(new AuthLog(processId, custId, authItem.getCode(), accAuth.getExpiredTime(), new Date()));
		}
		creditCatProcessManager.itemDone(new AuthItem(authItem.getCode()), processId);
		
	}

	@Override
	public List<AuthAccumulation> findUnCrawlAccumulation() {
		return authAccumulationService.findUnCrawl();
	}

	@Override
	public void updateAccumulationCrawlerState(AuthAccumulation authAccumulation) throws Exception {
	    this.crawAuthAccumulation(authAccumulation);
	}
	
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    private void itemFail(Long processId, Long custId, AuthItemEnum authItem, Integer type) throws Exception{
        if(type == AuthAccEnum.SOCIAL.getCode()){
            AuthSocial authAcc = authSocialService.findByProcessId(processId);
            AuthSocial authSocial = new AuthSocial(
                        authAcc.getAuthSocialId(),
                        null,
                        AuthAccumulationStatusEnum.AUTH_FAIL.getCode(),
                        CustIsRealEnum.No.getCode());
            authSocialService.update(authSocial);
        }
        else if(type == AuthAccEnum.ACCUMULATION.getCode()){//公积金
            AuthAccumulation authAcc = authAccumulationService.findByProccessId(processId);
            AuthAccumulation accAuth = new AuthAccumulation(
                        authAcc.getAuthAccId(),
                        null,
                        AuthAccumulationStatusEnum.AUTH_FAIL.getCode(),CustIsRealEnum.No.getCode());
            authAccumulationService.update(accAuth);
        }
    }

    @Log
    private void crawlSocial(AuthSocial obj) throws Exception {
        AccDetail accQuery  = null;
        Cust param = new Cust();
        param.setLastProccessId(obj.getProcessId());
        List<Cust> resultCustList = custService.find(param);
        if (Utility.isNullOrEmpty(resultCustList)) {
            return;
        }
        Cust cust = resultCustList.get(0);
        if (StringUtils.isEmpty(cust.getCustIdno())) {
            throw new BaseException("身份证不能为空");
        }
        if (StringUtils.isEmpty(obj.getSocalCity())) {
            throw new BaseException("城市不能为空");
        }
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("bustype", "");
        params.put("city", obj.getSocalCity());
        params.put("identitycard", cust.getCustIdno());
        try {
            accQuery = socailService.accQuery(obj.getSocalCity(), params);
        } catch (BirdRequestFailException birdExeception) {//业务异常
            itemFail(cust.getLastProccessId(), cust.getCustId(), AuthItemEnum.SOCIAL_CREDIT, AuthAccEnum.SOCIAL.getCode());
        } catch (BaseException baseException) {//网络异常
            return;
        }
        if (ObjectUtils.equals(null, accQuery)) {
            return;
        }
        String busIdentityCard = accQuery.getBusIdentityCard();
        String identityCard = accQuery.getIdentityCard();
        if (StringUtils.isEmpty(identityCard) || CommonUtil.certNoCompare(busIdentityCard, identityCard)) { //社保认证成功
            itemDone(cust.getLastProccessId(), cust.getCustId(), AuthItemEnum.SOCIAL_CREDIT, AuthAccEnum.SOCIAL.getCode());
        } else { //认证失贩
            itemFail(cust.getLastProccessId(), cust.getCustId(), AuthItemEnum.SOCIAL_CREDIT, AuthAccEnum.SOCIAL.getCode());
        }
    }
    
    @Log
    private void crawAuthAccumulation(AuthAccumulation obj) throws Exception {
        if (obj == null) {
            throw new Exception("公积金信息不能为空");
        }
        if (StringUtils.isEmpty(obj.getAccCity())) {
            throw new Exception(MessageFormat.format("processId为{0}的公积金城市为空", obj.getProccessId()));
        }
        if (obj.getCustId() == null) {
            throw new Exception(MessageFormat.format("processId为{0}的客户信息为空", obj.getProccessId()));
        }
        if (StringUtils.isEmpty(obj.getCustIdno())) {
            throw new Exception(MessageFormat.format("custId为{0}的身份证号为空", obj.getCustId()));
        }

        AccDetail crawlStateResult = null;
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("identitycard", obj.getCustIdno());
        try {
            crawlStateResult = accumulationService.accQuery(obj.getAccCity(), param);
            if (crawlStateResult != null) {
                String identityCard = crawlStateResult.getIdentityCard();
                String busIdentityCard = crawlStateResult.getBusIdentityCard();
                if (StringUtils.isEmpty(identityCard) || (CommonUtil.certNoCompare(identityCard, busIdentityCard))) {
                    itemDone(obj.getProccessId(), obj.getCustId(), AuthItemEnum.FUND_CREDIT,
                        AuthAccEnum.ACCUMULATION.getCode());
                } else {
                    itemFail(obj.getProccessId(), obj.getCustId(), AuthItemEnum.FUND_CREDIT,
                        AuthAccEnum.ACCUMULATION.getCode());
                }
            }
        } catch (BirdRequestFailException e) {
            itemFail(obj.getProccessId(), obj.getCustId(), AuthItemEnum.FUND_CREDIT, AuthAccEnum.ACCUMULATION.getCode());
        } catch (BaseException ex) {
            return;
        }

    }

    @Log
    @Override
    public List<AuthSocial> findAlreadyLoginAuthSocial() {
        List<AuthSocial> findAlreadyLoginAuthSocial = authSocialService.findAlreadyLoginAuthSocial();
        return findAlreadyLoginAuthSocial;
    }

    @Override
    public void updateSocialCrawlState(AuthSocial param) throws Exception {
        this.crawlSocial(param);
    }

}
